package business.global.pk.ddz.cardtype.util;

import business.ddz.c2s.cclass.DDZ_define;
import business.global.pk.alg.params.BaseOpCard;
import business.global.pk.alg.params.BasePKParameter;
import business.global.pk.alg.util.BasePKALGUtil;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhujianming
 * @date 2020-07-14 09:28
 * 斗地主算法工具
 */
public class DDZALGUtil extends BasePKALGUtil {

    private static class Singleton {
        private final static DDZALGUtil instance = new DDZALGUtil();
    }

    public static DDZALGUtil getInstance() {
        return DDZALGUtil.Singleton.instance;
    }

    /**
     * 是否是火箭
     *
     * @param lastOpCardType 上回合的类型
     * @param lastCardList 牌列表
     * @return 是否是火箭
     */
    public boolean isRocket(int lastOpCardType, ArrayList<Integer> lastCardList) {
        //四带一可以压所有，除了3A炸
        List<Integer> aCeCard = Arrays.asList(0x41, 0x42);//火箭
        return lastOpCardType == DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_ZHADAN.value() && lastCardList.containsAll(aCeCard);
    }

    /**
     * 检测对子
     * @return
     */
    public BaseOpCard checkAPair(BasePKParameter basePKParameter){
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        if(cloneOpTypeCardList.size()==2){
            Map<Integer, Long> group = groupingCountByCardValue(cloneOpTypeCardList);
            boolean existAPair = group.entrySet().stream().anyMatch(n -> n.getKey() > basePKParameter.compareValue && n.getValue() == 2);
            if(existAPair){
                return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_DUIZI.value(),0,cloneOpTypeCardList,getCardValue(cloneOpTypeCardList.get(0)));
            }
        }
        return null;
    }

    /**
     * 检测4带1
     * @return
     */
    public BaseOpCard checkFourWithA(BasePKParameter basePKParameter){
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        if(cloneOpTypeCardList.size()==5){
            Map<Integer, Long> group = groupingCountByCardValue(cloneOpTypeCardList);
            Optional<Integer> first = group.entrySet().stream().filter(n -> n.getKey() > basePKParameter.compareValue && n.getValue() == 4).map(Map.Entry::getKey).findFirst();
            if(first.isPresent()){
                return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_4DAI1.value(),1,cloneOpTypeCardList,first.get());
            }
        }
        return null;
    }

    /**
     * 检测4带1对
     * @return
     */
    public BaseOpCard checkFourWithPairs(BasePKParameter basePKParameter){
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        if(cloneOpTypeCardList.size()==6){
            Map<Integer, Long> group = groupingCountByCardValue(cloneOpTypeCardList);
            Optional<Integer> first = group.entrySet().stream().filter(n -> n.getKey() > basePKParameter.compareValue && n.getValue() == 4).map(Map.Entry::getKey).findFirst();
            if(first.isPresent()&&group.containsValue(2L)){
                return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_4DAI21.value(),2,cloneOpTypeCardList,first.get());
            }
        }
        return null;
    }

    /**
     * 检测4带2
     * @return
     */
    public BaseOpCard checkFourWithTwo(BasePKParameter basePKParameter){
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        if(cloneOpTypeCardList.size()==6){
            Map<Integer, Long> group = groupingCountByCardValue(cloneOpTypeCardList);
            Optional<Integer> first = group.entrySet().stream().filter(n -> n.getKey() > basePKParameter.compareValue && n.getValue() == 4).map(Map.Entry::getKey).findFirst();
            if(first.isPresent()){
                return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_4DAI2.value(),2,cloneOpTypeCardList,first.get());
            }
        }
        return null;
    }

    /**
     * 检测4带2对
     * @return
     */
    public BaseOpCard checkFourWithTwoPairs(BasePKParameter basePKParameter){
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        if(cloneOpTypeCardList.size()==8){
            Map<Integer, Long> group = groupingCountByCardValue(cloneOpTypeCardList);
            Optional<Integer> first = group.entrySet().stream().filter(n -> n.getKey() > basePKParameter.compareValue && n.getValue() == 4).map(Map.Entry::getKey).findFirst();
            if(first.isPresent() && !group.containsValue(1L) && !group.containsValue(3L)){
                return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_4DAI4.value(),4,cloneOpTypeCardList,first.get());
            }
        }
        return null;
    }

    /**
     * 检测连队
     * @param basePKParameter
     * @return
     */
    public BaseOpCard checkMultiPairs(BasePKParameter basePKParameter) {
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        int length = basePKParameter.lastTripleNum;
        if(length==0 && cloneOpTypeCardList.size()<6){
            return null;
        }
        if(length!=0 && cloneOpTypeCardList.size()/2!=length){
            return null;
        }
        if (cloneOpTypeCardList.stream().anyMatch(twoValueList::contains)) {
            return null;
        }
        Map<Integer, List<Integer>> valueListMap = groupingListByCardValue(cloneOpTypeCardList);
        List<Integer> straightList = valueListMap.entrySet().stream().filter(n -> n.getValue().size() == 2).map(Map.Entry::getKey).collect(Collectors.toList());
        Integer minCardKey = straightList.stream().reduce(Integer::min).get();
        Integer maxCardKey = straightList.stream().reduce(Integer::max).get();
        boolean isStraight = (straightList.size() == cloneOpTypeCardList.size() / 2) && maxCardKey - minCardKey == (cloneOpTypeCardList.size() / 2) - 1;
        if(isStraight && minCardKey>basePKParameter.compareValue){
            return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_LIANDUI.value(),0,cloneOpTypeCardList,minCardKey,cloneOpTypeCardList.size()/2);
        }
        return null;
    }

    /**
     * 检测单张
     * @param basePKParameter
     * @return
     */
    public BaseOpCard checkSingle(BasePKParameter basePKParameter){
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        if(cloneOpTypeCardList.size()==1){
            boolean existTrue = getCardValue(cloneOpTypeCardList.get(0)) > basePKParameter.compareValue;
            if(existTrue){
                return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_SINGLECARD.value(),0,cloneOpTypeCardList,getCardValue(cloneOpTypeCardList.get(0)));
            }
        }
        return null;
    }

    /**
     * 检测顺子
     * @param basePKParameter
     * @return
     */
    public BaseOpCard checkStraight(BasePKParameter basePKParameter) {
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        int length = basePKParameter.lastTripleNum;
        if(length==0 && cloneOpTypeCardList.size()<5){
            return null;
        }
        if(length!=0 && cloneOpTypeCardList.size()!=length){
            return null;
        }
        if (cloneOpTypeCardList.stream().anyMatch(twoValueList::contains)) {
            return null;
        }
        List<Integer> straightList = cloneOpTypeCardList.stream().map(this::getCardValue).collect(Collectors.toList());
        Integer minCardKey = straightList.stream().reduce(Integer::min).get();
        Integer maxCardKey = straightList.stream().reduce(Integer::max).get();
        boolean isStraight = maxCardKey - minCardKey == (cloneOpTypeCardList.size() - 1);
        if(isStraight && minCardKey>basePKParameter.compareValue){
            return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_SHUNZI.value(),0,cloneOpTypeCardList,minCardKey,cloneOpTypeCardList.size());
        }
        return null;
    }

    /**
     * 检测3不带
     * @param basePKParameter
     * @return
     */
    public BaseOpCard checkThreeZone(BasePKParameter basePKParameter){
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        if(cloneOpTypeCardList.size()==3){
            Map<Integer, Long> group = groupingCountByCardValue(cloneOpTypeCardList);
            boolean existAPair = group.entrySet().stream().anyMatch(n -> n.getKey() > basePKParameter.compareValue && n.getValue() == 3);
            if(existAPair){
                return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_3BUDAI.value(),0,cloneOpTypeCardList,getCardValue(cloneOpTypeCardList.get(0)));
            }
        }
        return null;
    }

    /**
     * 检测3带1
     * @param basePKParameter
     * @return
     */
    public BaseOpCard checkThreeZoneWithA(BasePKParameter basePKParameter){
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        if(cloneOpTypeCardList.size()==4){
            Map<Integer, Long> group = groupingCountByCardValue(cloneOpTypeCardList);
            Optional<Integer> first = group.entrySet().stream().filter(n -> n.getKey() > basePKParameter.compareValue && n.getValue() == 3).map(Map.Entry::getKey).findFirst();
            if(first.isPresent()){
                return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_3DAI1.value(),0,cloneOpTypeCardList,getCardValue(first.get()));
            }
        }
        return null;
    }

    /**
     * 检测3带1对
     * @param basePKParameter
     * @return
     */
    public BaseOpCard checkThreeZoneWithPairs(BasePKParameter basePKParameter){
        ArrayList<Integer> cloneOpTypeCardList = basePKParameter.getCloneOpTypeCardList();
        if(cloneOpTypeCardList.size()==5){
            Map<Integer, Long> group = groupingCountByCardValue(cloneOpTypeCardList);
            Optional<Integer> first = group.entrySet().stream().filter(n -> n.getKey() > basePKParameter.compareValue && n.getValue() == 3).map(Map.Entry::getKey).findFirst();
            if(first.isPresent() &&group.containsValue(2L)){
                return BaseOpCard.make(DDZ_define.DDZ_CARD_TYPE.DDZ_CARD_TYPE_3DAI2.value(),0,cloneOpTypeCardList,getCardValue(first.get()));
            }
        }
        return null;
    }

    /**
     * 获取飞机不带
     *
     * @param basePKParameter 牌列表
     * @return 飞机
     */
    public BaseOpCard checkPlaneBuDai(BasePKParameter basePKParameter) {
        int compareValue = basePKParameter.compareValue;
        ArrayList<Integer> cardList = basePKParameter.getCloneOpTypeCardList();
        int lastTripleNum = basePKParameter.lastTripleNum == 0 ? -1 : basePKParameter.lastTripleNum;
        List<BaseOpCard> baseOpCards = getPlane(cardList, 0, false, lastTripleNum, compareValue,false);
        BaseOpCard firstPlane = getFirstPlane(0, baseOpCards,1);
        if (firstPlane != null && firstPlane.cardList.size() >= 6) {
            firstPlane.opCardType = basePKParameter.targetType;
            firstPlane.daiNum = 0;
            return firstPlane;
        }
        return null;
    }

    /**
     * 获取飞机带一张
     *
     * @param basePKParameter 牌列表
     * @return 飞机
     */
    public BaseOpCard checkPlaneWithA(BasePKParameter basePKParameter,int sort) {
        int compareValue = basePKParameter.compareValue;
        ArrayList<Integer> cardList = basePKParameter.getCloneOpTypeCardList();
        int lastTripleNum = basePKParameter.lastTripleNum == 0 ? -1 : basePKParameter.lastTripleNum;
        List<BaseOpCard> baseOpCards = getPlane(cardList, 1, false, lastTripleNum, compareValue,false);
        BaseOpCard firstPlane = getFirstPlane(1, baseOpCards,sort);
        if (firstPlane != null && firstPlane.cardList.size() >= 8) {
            firstPlane.opCardType = basePKParameter.targetType;
            firstPlane.daiNum = 0;
            return firstPlane;
        }
        return null;
    }

    /**
     * 获取飞机带一对
     *
     * @param basePKParameter 牌列表
     * @return 飞机
     */
    public BaseOpCard checkPlaneWithPairs(BasePKParameter basePKParameter) {
        int compareValue = basePKParameter.compareValue;
        ArrayList<Integer> cardList = basePKParameter.getCloneOpTypeCardList();
        int lastTripleNum = basePKParameter.lastTripleNum == 0 ? -1 : basePKParameter.lastTripleNum;
        List<BaseOpCard> baseOpCards = getPlane(cardList, 2, true, lastTripleNum, compareValue,false);
        BaseOpCard firstPlane = getFirstPlane(2, baseOpCards,0);
        if (firstPlane != null && firstPlane.cardList.size() >= 10) {
            firstPlane.opCardType = basePKParameter.targetType;
            firstPlane.daiNum = 0;
            return firstPlane;
        }
        return null;
    }

}
